home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / base / netkit-b.07a / netkit-b / NetKit-B-0.07A / ftp / cmds.c next >
Encoding:
C/C++ Source or Header  |  1996-07-21  |  41.1 KB  |  2,229 lines

  1. /*
  2.  * Copyright (c) 1985, 1989 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. /*
  35.  * from: @(#)cmds.c    5.26 (Berkeley) 3/5/91
  36.  */
  37. char cmds_rcsid[] = 
  38.    "$Id: cmds.c,v 1.7 1996/07/21 09:28:46 dholland Exp $";
  39.  
  40. /*
  41.  * FTP User Program -- Command Routines.
  42.  */
  43. #include <sys/param.h>
  44. #include <sys/wait.h>
  45. #include <sys/stat.h>
  46. #include <sys/socket.h>
  47.  
  48. #include <arpa/ftp.h>
  49.  
  50. #include <signal.h>
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include <errno.h>
  54. #include <netdb.h>
  55. #include <ctype.h>
  56. #include <time.h>
  57. #include <string.h>
  58. #include <unistd.h>
  59. #include <netinet/in.h>
  60.  
  61. #include "ftp_var.h"
  62. #include "pathnames.h"
  63. #include "cmds.h"
  64.  
  65. extern    char *globerr;
  66. extern    char **ftpglob();
  67. extern    char *home;
  68. extern    char *remglob();
  69. extern    char *getenv();
  70. extern    char *index();
  71. extern    char *rindex();
  72. extern    char *strerror();
  73. extern    int  errno;
  74. extern off_t restart_point;
  75. extern char reply_string[];
  76.  
  77. char *mname;
  78. sigjmp_buf jabort;
  79. char *dotrans(), *domap();
  80. void intr(int);
  81.  
  82. static int globulize(char **cpp);
  83. static int confirm(char *cmd, char *file);
  84. static int getit(int argc, char *argv[], int restartit, char *mode);
  85. static void quote1(char *initial, int argc, char **argv);
  86.  
  87.  
  88. /*
  89.  * `Another' gets another argument, and stores the new argc and argv.
  90.  * It reverts to the top level (via main.c's intr()) on EOF/error.
  91.  *
  92.  * Returns false if no new arguments have been added.
  93.  */
  94. int
  95. another(int *pargc, char ***pargv, const char *prompt)
  96. {
  97.     int len = strlen(line), ret;
  98.  
  99.     if (len >= sizeof(line) - 3) {
  100.         printf("sorry, arguments too long\n");
  101.         intr(0);
  102.     }
  103.     printf("(%s) ", prompt);
  104.     line[len++] = ' ';
  105.     if (fgets(&line[len], sizeof(line) - len, stdin) == NULL)
  106.         intr(0);
  107.     len += strlen(&line[len]);
  108.     if (len > 0 && line[len - 1] == '\n')
  109.         line[len - 1] = '\0';
  110.     makeargv();
  111.     ret = margc > *pargc;
  112.     *pargc = margc;
  113.     *pargv = margv;
  114.     return ret;
  115. }
  116.  
  117. /*
  118.  * Connect to peer server and
  119.  * auto-login, if possible.
  120.  */
  121. void
  122. setpeer(int argc, char *argv[])
  123. {
  124.     char *host, *hookup();
  125.     short port;
  126.  
  127.     if (connected) {
  128.         printf("Already connected to %s, use close first.\n",
  129.             hostname);
  130.         code = -1;
  131.         return;
  132.     }
  133.     if (argc < 2)
  134.         (void) another(&argc, &argv, "to");
  135.     if (argc < 2 || argc > 3) {
  136.         printf("usage: %s host-name [port]\n", argv[0]);
  137.         code = -1;
  138.         return;
  139.     }
  140.     port = ftp_port;
  141.     if (argc > 2) {
  142.         port = atoi(argv[2]);
  143.         if (port <= 0) {
  144.             printf("%s: bad port number-- %s\n", argv[1], argv[2]);
  145.             printf ("usage: %s host-name [port]\n", argv[0]);
  146.             code = -1;
  147.             return;
  148.         }
  149.         port = htons(port);
  150.     }
  151.     host = hookup(argv[1], port);
  152.     if (host) {
  153. /*        int overbose; */
  154.  
  155.         connected = 1;
  156.         /*
  157.          * Set up defaults for FTP.
  158.          */
  159.         (void) strcpy(typename, "ascii"), type = TYPE_A;
  160.         curtype = TYPE_A;
  161.         (void) strcpy(formname, "non-print"), form = FORM_N;
  162.         (void) strcpy(modename, "stream"), mode = MODE_S;
  163.         (void) strcpy(structname, "file"), stru = STRU_F;
  164.         (void) strcpy(bytename, "8"), bytesize = 8;
  165.         if (autologin)
  166.             (void) login(argv[1]);
  167.  
  168. #if defined(unix) && NBBY == 8
  169. /*
  170.  * this ifdef is to keep someone form "porting" this to an incompatible
  171.  * system and not checking this out. This way they have to think about it.
  172.  */
  173.         overbose = verbose;
  174.         if (debug == 0)
  175.             verbose = -1;
  176.         if (command("SYST") == COMPLETE && overbose) {
  177.             register char *cp, c = 0;
  178.             cp = index(reply_string+4, ' ');
  179.             if (cp == NULL)
  180.                 cp = index(reply_string+4, '\r');
  181.             if (cp) {
  182.                 if (cp[-1] == '.')
  183.                     cp--;
  184.                 c = *cp;
  185.                 *cp = '\0';
  186.             }
  187.  
  188.             printf("Remote system type is %s.\n",
  189.                 reply_string+4);
  190.             if (cp)
  191.                 *cp = c;
  192.         }
  193.         if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
  194.             if (proxy)
  195.                 unix_proxy = 1;
  196.             else
  197.                 unix_server = 1;
  198.             /*
  199.              * Set type to 0 (not specified by user),
  200.              * meaning binary by default, but don't bother
  201.              * telling server.  We can use binary
  202.              * for text files unless changed by the user.
  203.              */
  204.             type = 0;
  205.             (void) strcpy(typename, "binary");
  206.             if (overbose)
  207.                 printf("Using %s mode to transfer files.\n",
  208.                 typename);
  209.         } else {
  210.             if (proxy)
  211.                 unix_proxy = 0;
  212.             else
  213.                 unix_server = 0;
  214.             if (overbose && 
  215.                 !strncmp(reply_string, "215 TOPS20", 10))
  216.                 printf(
  217. "Remember to set tenex mode when transfering binary files from this machine.\n");
  218.         }
  219.         verbose = overbose;
  220. #endif /* unix */
  221.     }
  222. }
  223.  
  224. struct    types {
  225.     char    *t_name;
  226.     char    *t_mode;
  227.     int    t_type;
  228.     char    *t_arg;
  229. } types[] = {
  230.     { "ascii",    "A",    TYPE_A,    0 },
  231.     { "binary",    "I",    TYPE_I,    0 },
  232.     { "image",    "I",    TYPE_I,    0 },
  233.     { "ebcdic",    "E",    TYPE_E,    0 },
  234.     { "tenex",    "L",    TYPE_L,    bytename },
  235.     { NULL, NULL, 0, 0 }
  236. };
  237.  
  238. /*
  239.  * Set transfer type.
  240.  */
  241. void
  242. settype(int argc, char *argv[])
  243. {
  244.     register struct types *p;
  245.     int comret;
  246.  
  247.     if (argc > 2) {
  248.         char *sep;
  249.  
  250.         printf("usage: %s [", argv[0]);
  251.         sep = " ";
  252.         for (p = types; p->t_name; p++) {
  253.             printf("%s%s", sep, p->t_name);
  254.             sep = " | ";
  255.         }
  256.         printf(" ]\n");
  257.         code = -1;
  258.         return;
  259.     }
  260.     if (argc < 2) {
  261.         printf("Using %s mode to transfer files.\n", typename);
  262.         code = 0;
  263.         return;
  264.     }
  265.     for (p = types; p->t_name; p++)
  266.         if (strcmp(argv[1], p->t_name) == 0)
  267.             break;
  268.     if (p->t_name == 0) {
  269.         printf("%s: unknown mode\n", argv[1]);
  270.         code = -1;
  271.         return;
  272.     }
  273.     if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
  274.         comret = command("TYPE %s %s", p->t_mode, p->t_arg);
  275.     else
  276.         comret = command("TYPE %s", p->t_mode);
  277.     if (comret == COMPLETE) {
  278.         (void) strcpy(typename, p->t_name);
  279.         curtype = type = p->t_type;
  280.     }
  281. }
  282.  
  283. /*
  284.  * Internal form of settype; changes current type in use with server
  285.  * without changing our notion of the type for data transfers.
  286.  * Used to change to and from ascii for listings.
  287.  */
  288. void
  289. changetype(int newtype, int show)
  290. {
  291.     register struct types *p;
  292.     int comret, oldverbose = verbose;
  293.     int oldtick = tick;
  294.  
  295.     if (newtype == 0)
  296.         newtype = TYPE_I;
  297.     if (newtype == curtype)
  298.         return;
  299.     if (debug == 0 && show == 0)
  300.         verbose = 0;
  301.     tick = 0;
  302.     for (p = types; p->t_name; p++)
  303.         if (newtype == p->t_type)
  304.             break;
  305.     if (p->t_name == 0) {
  306.         printf("ftp: internal error: unknown type %d\n", newtype);
  307.         return;
  308.     }
  309.     if (newtype == TYPE_L && bytename[0] != '\0')
  310.         comret = command("TYPE %s %s", p->t_mode, bytename);
  311.     else
  312.         comret = command("TYPE %s", p->t_mode);
  313.     if (comret == COMPLETE)
  314.         curtype = newtype;
  315.     verbose = oldverbose;
  316.     tick = oldtick;
  317. }
  318.  
  319. char *stype[] = {
  320.     "type",
  321.     "",
  322.     0
  323. };
  324.  
  325. /*
  326.  * Set binary transfer type.
  327.  */
  328. /*VARARGS*/
  329. void
  330. setbinary(int argc, char *argv[])
  331. {
  332.     stype[1] = "binary";
  333.     settype(2, stype);
  334. }
  335.  
  336. /*
  337.  * Set ascii transfer type.
  338.  */
  339. /*VARARGS*/
  340. void
  341. setascii(int argc, char *argv[])
  342. {
  343.     stype[1] = "ascii";
  344.     settype(2, stype);
  345. }
  346.  
  347. /*
  348.  * Set tenex transfer type.
  349.  */
  350. /*VARARGS*/
  351. void
  352. settenex(int argc, char *argv[])
  353. {
  354.     stype[1] = "tenex";
  355.     settype(2, stype);
  356. }
  357.  
  358. /*
  359.  * Set file transfer mode.
  360.  */
  361. /*ARGSUSED*/
  362. void
  363. setmode(argc, argv)
  364.     int argc;
  365.     char *argv[];
  366. {
  367.  
  368.     printf("We only support %s mode, sorry.\n", modename);
  369.     code = -1;
  370. }
  371.  
  372. /*
  373.  * Set file transfer format.
  374.  */
  375. /*ARGSUSED*/
  376. void
  377. setform(int argc, char *argv[])
  378. {
  379.  
  380.     printf("We only support %s format, sorry.\n", formname);
  381.     code = -1;
  382. }
  383.  
  384. /*
  385.  * Set file transfer structure.
  386.  */
  387. /*ARGSUSED*/
  388. void
  389. setstruct(int argc, char *argv[])
  390. {
  391.     printf("We only support %s structure, sorry.\n", structname);
  392.     code = -1;
  393. }
  394.  
  395. /*
  396.  * Send a single file.
  397.  */
  398. void
  399. put(argc, argv)
  400.     int argc;
  401.     char *argv[];
  402. {
  403.     char *cmd;
  404.     int loc = 0;
  405.     char *oldargv1, *oldargv2;
  406.  
  407.     if (argc == 2) {
  408.         argc++;
  409.         argv[2] = argv[1];
  410.         loc++;
  411.     }
  412.     if (argc < 2 && !another(&argc, &argv, "local-file"))
  413.         goto usage;
  414.     if (argc < 3 && !another(&argc, &argv, "remote-file")) {
  415. usage:
  416.         printf("usage: %s local-file remote-file\n", argv[0]);
  417.         code = -1;
  418.         return;
  419.     }
  420.     oldargv1 = argv[1];
  421.     oldargv2 = argv[2];
  422.     if (!globulize(&argv[1])) {
  423.         code = -1;
  424.         return;
  425.     }
  426.     /*
  427.      * If "globulize" modifies argv[1], and argv[2] is a copy of
  428.      * the old argv[1], make it a copy of the new argv[1].
  429.      */
  430.     if (argv[1] != oldargv1 && argv[2] == oldargv1) {
  431.         argv[2] = argv[1];
  432.     }
  433.     cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
  434.     if (loc && ntflag) {
  435.         argv[2] = dotrans(argv[2]);
  436.     }
  437.     if (loc && mapflag) {
  438.         argv[2] = domap(argv[2]);
  439.     }
  440.     sendrequest(cmd, argv[1], argv[2],
  441.         argv[1] != oldargv1 || argv[2] != oldargv2);
  442. }
  443.  
  444. void mabort(int);
  445.  
  446. /*
  447.  * Send multiple files.
  448.  */
  449. void
  450. mput(argc, argv)
  451.     int argc;
  452.     char **argv;
  453. {
  454.     extern sigjmp_buf jabort;
  455.     register int i;
  456.     void (*oldintr)(int);
  457.     int ointer;
  458.     char *tp;
  459.  
  460.     if (argc < 2 && !another(&argc, &argv, "local-files")) {
  461.         printf("usage: %s local-files\n", argv[0]);
  462.         code = -1;
  463.         return;
  464.     }
  465.     mname = argv[0];
  466.     mflag = 1;
  467.     oldintr = signal(SIGINT, mabort);
  468.     (void) sigsetjmp(jabort, 1);
  469.     if (proxy) {
  470.         char *cp, *tp2, tmpbuf[MAXPATHLEN];
  471.  
  472.         while ((cp = remglob(argv,0)) != NULL) {
  473.             if (*cp == 0) {
  474.                 mflag = 0;
  475.                 continue;
  476.             }
  477.             if (mflag && confirm(argv[0], cp)) {
  478.                 tp = cp;
  479.                 if (mcase) {
  480.                     while (*tp && !islower(*tp)) {
  481.                         tp++;
  482.                     }
  483.                     if (!*tp) {
  484.                         tp = cp;
  485.                         tp2 = tmpbuf;
  486.                         while ((*tp2 = *tp) != '\0') {
  487.                              if (isupper(*tp2)) {
  488.                                 *tp2 = 'a' + *tp2 - 'A';
  489.                              }
  490.                              tp++;
  491.                              tp2++;
  492.                         }
  493.                     }
  494.                     tp = tmpbuf;
  495.                 }
  496.                 if (ntflag) {
  497.                     tp = dotrans(tp);
  498.                 }
  499.                 if (mapflag) {
  500.                     tp = domap(tp);
  501.                 }
  502.                 sendrequest((sunique) ? "STOU" : "STOR",
  503.                     cp, tp, cp != tp || !interactive);
  504.                 if (!mflag && fromatty) {
  505.                     ointer = interactive;
  506.                     interactive = 1;
  507.                     if (confirm("Continue with","mput")) {
  508.                         mflag++;
  509.                     }
  510.                     interactive = ointer;
  511.                 }
  512.             }
  513.         }
  514.         (void) signal(SIGINT, oldintr);
  515.         mflag = 0;
  516.         return;
  517.     }
  518.     for (i = 1; i < argc; i++) {
  519.         register char **cpp, **gargs;
  520.  
  521.         if (!doglob) {
  522.             if (mflag && confirm(argv[0], argv[i])) {
  523.                 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
  524.                 tp = (mapflag) ? domap(tp) : tp;
  525.                 sendrequest((sunique) ? "STOU" : "STOR",
  526.                     argv[i], tp, tp != argv[i] || !interactive);
  527.                 if (!mflag && fromatty) {
  528.                     ointer = interactive;
  529.                     interactive = 1;
  530.                     if (confirm("Continue with","mput")) {
  531.                         mflag++;
  532.                     }
  533.                     interactive = ointer;
  534.                 }
  535.             }
  536.             continue;
  537.         }
  538.         gargs = ftpglob(argv[i]);
  539.         if (globerr != NULL) {
  540.             printf("%s\n", globerr);
  541.             if (gargs) {
  542.                 blkfree(gargs);
  543.                 free((char *)gargs);
  544.             }
  545.             continue;
  546.         }
  547.         for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
  548.             if (mflag && confirm(argv[0], *cpp)) {
  549.                 tp = (ntflag) ? dotrans(*cpp) : *cpp;
  550.                 tp = (mapflag) ? domap(tp) : tp;
  551.                 sendrequest((sunique) ? "STOU" : "STOR",
  552.                     *cpp, tp, *cpp != tp || !interactive);
  553.                 if (!mflag && fromatty) {
  554.                     ointer = interactive;
  555.                     interactive = 1;
  556.                     if (confirm("Continue with","mput")) {
  557.                         mflag++;
  558.                     }
  559.                     interactive = ointer;
  560.                 }
  561.             }
  562.         }
  563.         if (gargs != NULL) {
  564.             blkfree(gargs);
  565.             free((char *)gargs);
  566.         }
  567.     }
  568.     (void) signal(SIGINT, oldintr);
  569.     mflag = 0;
  570. }
  571.  
  572. void
  573. reget(argc, argv)
  574.     int argc;
  575.     char *argv[];
  576. {
  577.     (void) getit(argc, argv, 1, "r+w");
  578. }
  579.  
  580. void
  581. get(argc, argv)
  582.     int argc;
  583.     char *argv[];
  584. {
  585.     (void) getit(argc, argv, 0, restart_point ? "r+w" : "w" );
  586. }
  587.  
  588. /*
  589.  * Receive one file.
  590.  */
  591. static int
  592. getit(int argc, char *argv[], int restartit, char *mode)
  593. {
  594.     int loc = 0;
  595.     char *oldargv1, *oldargv2;
  596.  
  597.     if (argc == 2) {
  598.         argc++;
  599.         argv[2] = argv[1];
  600.         loc++;
  601.     }
  602.     if (argc < 2 && !another(&argc, &argv, "remote-file"))
  603.         goto usage;
  604.     if (argc < 3 && !another(&argc, &argv, "local-file")) {
  605. usage:
  606.         printf("usage: %s remote-file [ local-file ]\n", argv[0]);
  607.         code = -1;
  608.         return (0);
  609.     }
  610.     oldargv1 = argv[1];
  611.     oldargv2 = argv[2];
  612.     if (!globulize(&argv[2])) {
  613.         code = -1;
  614.         return (0);
  615.     }
  616.     if (loc && mcase) {
  617.         char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
  618.  
  619.         while (*tp && !islower(*tp)) {
  620.             tp++;
  621.         }
  622.         if (!*tp) {
  623.             tp = argv[2];
  624.             tp2 = tmpbuf;
  625.             while ((*tp2 = *tp) != '\0') {
  626.                 if (isupper(*tp2)) {
  627.                     *tp2 = 'a' + *tp2 - 'A';
  628.                 }
  629.                 tp++;
  630.                 tp2++;
  631.             }
  632.             argv[2] = tmpbuf;
  633.         }
  634.     }
  635.     if (loc && ntflag)
  636.         argv[2] = dotrans(argv[2]);
  637.     if (loc && mapflag)
  638.         argv[2] = domap(argv[2]);
  639.     if (restartit) {
  640.         struct stat stbuf;
  641.         int ret;
  642.  
  643.         ret = stat(argv[2], &stbuf);
  644.         if (restartit == 1) {
  645.             if (ret < 0) {
  646.                 fprintf(stderr, "local: %s: %s\n", argv[2],
  647.                     strerror(errno));
  648.                 return (0);
  649.             }
  650.             restart_point = stbuf.st_size;
  651.         } else {
  652.             if (ret == 0) {
  653.                 int overbose;
  654.  
  655.                 overbose = verbose;
  656.                 if (debug == 0)
  657.                     verbose = -1;
  658.                 if (command("MDTM %s", argv[1]) == COMPLETE) {
  659.                     int yy, mo, day, hour, min, sec;
  660.                     struct tm *tm;
  661.                     verbose = overbose;
  662.                     sscanf(reply_string,
  663.                         "%*s %04d%02d%02d%02d%02d%02d",
  664.                         &yy, &mo, &day, &hour, &min, &sec);
  665.                     tm = gmtime(&stbuf.st_mtime);
  666.                     tm->tm_mon++;
  667. /* Indentation is misleading, but changes keep small. */
  668.                     if (tm->tm_year > yy%100)
  669.                         return (1);
  670.                     else if (tm->tm_year == yy%100)
  671.                         if (tm->tm_mon > mo)
  672.                             return (1);
  673.                     else if (tm->tm_mon == mo)
  674.                         if (tm->tm_mday > day)
  675.                             return (1);
  676.                     else if (tm->tm_mday == day)
  677.                         if (tm->tm_hour > hour)
  678.                             return (1);
  679.                     else if (tm->tm_hour == hour)
  680.                         if (tm->tm_min > min)
  681.                             return (1);
  682.                     else if (tm->tm_min == min)
  683.                         if (tm->tm_sec > sec)
  684.                             return (1);
  685.                 } else {
  686.                     printf("%s\n", reply_string);
  687.                     verbose = overbose;
  688.                     return (0);
  689.                 }
  690.             }
  691.         }
  692.     }
  693.  
  694.     recvrequest("RETR", argv[2], argv[1], mode,
  695.         argv[1] != oldargv1 || argv[2] != oldargv2);
  696.     restart_point = 0;
  697.     return (0);
  698. }
  699.  
  700. void
  701. mabort(int ignore)
  702. {
  703.     int ointer;
  704.     extern sigjmp_buf jabort;
  705.  
  706.     printf("\n");
  707.     (void) fflush(stdout);
  708.     if (mflag && fromatty) {
  709.         ointer = interactive;
  710.         interactive = 1;
  711.         if (confirm("Continue with", mname)) {
  712.             interactive = ointer;
  713.             siglongjmp(jabort,0);
  714.         }
  715.         interactive = ointer;
  716.     }
  717.     mflag = 0;
  718.     siglongjmp(jabort,0);
  719. }
  720.  
  721. /*
  722.  * Get multiple files.
  723.  */
  724. void
  725. mget(argc, argv)
  726.     int argc;
  727.     char **argv;
  728. {
  729.     extern sigjmp_buf jabort;
  730.     void (*oldintr)(int);
  731.     int ointer;
  732.     char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
  733.  
  734.     if (argc < 2 && !another(&argc, &argv, "remote-files")) {
  735.         printf("usage: %s remote-files\n", argv[0]);
  736.         code = -1;
  737.         return;
  738.     }
  739.     mname = argv[0];
  740.     mflag = 1;
  741.     oldintr = signal(SIGINT,mabort);
  742.     (void) sigsetjmp(jabort, 1);
  743.     while ((cp = remglob(argv,proxy)) != NULL) {
  744.         if (*cp == '\0') {
  745.             mflag = 0;
  746.             continue;
  747.         }
  748.         if (mflag && confirm(argv[0], cp)) {
  749.             tp = cp;
  750.             if (mcase) {
  751.                 while (*tp && !islower(*tp)) {
  752.                     tp++;
  753.                 }
  754.                 if (!*tp) {
  755.                     tp = cp;
  756.                     tp2 = tmpbuf;
  757.                     while ((*tp2 = *tp) != '\0') {
  758.                         if (isupper(*tp2)) {
  759.                             *tp2 = 'a' + *tp2 - 'A';
  760.                         }
  761.                         tp++;
  762.                         tp2++;
  763.                     }
  764.                 }
  765.                 tp = tmpbuf;
  766.             }
  767.             if (ntflag) {
  768.                 tp = dotrans(tp);
  769.             }
  770.             if (mapflag) {
  771.                 tp = domap(tp);
  772.             }
  773.             recvrequest("RETR", tp, cp, "w",
  774.                 tp != cp || !interactive);
  775.             if (!mflag && fromatty) {
  776.                 ointer = interactive;
  777.                 interactive = 1;
  778.                 if (confirm("Continue with","mget")) {
  779.                     mflag++;
  780.                 }
  781.                 interactive = ointer;
  782.             }
  783.         }
  784.     }
  785.     (void) signal(SIGINT,oldintr);
  786.     mflag = 0;
  787. }
  788.  
  789. char *
  790. remglob(argv,doswitch)
  791.     char *argv[];
  792.     int doswitch;
  793. {
  794.     char temp[16];
  795.     static char buf[MAXPATHLEN];
  796.     static FILE *ftemp = NULL;
  797.     static char **args;
  798.     int oldverbose, oldhash;
  799.     char *cp, *mode;
  800.  
  801.     if (!mflag) {
  802.         if (!doglob) {
  803.             args = NULL;
  804.         }
  805.         else {
  806.             if (ftemp) {
  807.                 (void) fclose(ftemp);
  808.                 ftemp = NULL;
  809.             }
  810.         }
  811.         return(NULL);
  812.     }
  813.     if (!doglob) {
  814.         if (args == NULL)
  815.             args = argv;
  816.         if ((cp = *++args) == NULL)
  817.             args = NULL;
  818.         return (cp);
  819.     }
  820.     if (ftemp == NULL) {
  821.         (void) strcpy(temp, _PATH_TMP);
  822.         (void) mktemp(temp);
  823.         oldverbose = verbose, verbose = 0;
  824.         oldhash = hash, hash = 0;
  825.         if (doswitch) {
  826.             pswitch(!proxy);
  827.         }
  828.         for (mode = "w"; *++argv != NULL; mode = "a")
  829.             recvrequest ("NLST", temp, *argv, mode, 0);
  830.         if (doswitch) {
  831.             pswitch(!proxy);
  832.         }
  833.         verbose = oldverbose; hash = oldhash;
  834.         ftemp = fopen(temp, "r");
  835.         (void) unlink(temp);
  836.         if (ftemp == NULL) {
  837.             printf("can't find list of remote files, oops\n");
  838.             return (NULL);
  839.         }
  840.     }
  841.     if (fgets(buf, sizeof (buf), ftemp) == NULL) {
  842.         (void) fclose(ftemp), ftemp = NULL;
  843.         return (NULL);
  844.     }
  845.     if ((cp = index(buf, '\n')) != NULL)
  846.         *cp = '\0';
  847.     return (buf);
  848. }
  849.  
  850. char *
  851. onoff(bool)
  852.     int bool;
  853. {
  854.  
  855.     return (bool ? "on" : "off");
  856. }
  857.  
  858. /*
  859.  * Show status.
  860.  */
  861. /*ARGSUSED*/
  862. void
  863. status(argc, argv)
  864.     int argc;
  865.     char *argv[];
  866. {
  867.     int i;
  868.  
  869.     if (connected)
  870.         printf("Connected to %s.\n", hostname);
  871.     else
  872.         printf("Not connected.\n");
  873.     if (!proxy) {
  874.         pswitch(1);
  875.         if (connected) {
  876.             printf("Connected for proxy commands to %s.\n", hostname);
  877.         }
  878.         else {
  879.             printf("No proxy connection.\n");
  880.         }
  881.         pswitch(0);
  882.     }
  883.     printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
  884.         modename, typename, formname, structname);
  885.     printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 
  886.         onoff(verbose), onoff(bell), onoff(interactive),
  887.         onoff(doglob));
  888.     printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
  889.         onoff(runique));
  890.     printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
  891.     if (ntflag) {
  892.         printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
  893.     }
  894.     else {
  895.         printf("Ntrans: off\n");
  896.     }
  897.     if (mapflag) {
  898.         printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
  899.     }
  900.     else {
  901.         printf("Nmap: off\n");
  902.     }
  903.     printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
  904.         onoff(hash), onoff(sendport));
  905.     printf("Tick counter printing: %s\n", onoff(tick));
  906.     if (macnum > 0) {
  907.         printf("Macros:\n");
  908.         for (i=0; i<macnum; i++) {
  909.             printf("\t%s\n",macros[i].mac_name);
  910.         }
  911.     }
  912.     code = 0;
  913. }
  914.  
  915. /*
  916.  * Set beep on cmd completed mode.
  917.  */
  918. /*VARARGS*/
  919. void
  920. setbell(int argc, char *argv[])
  921. {
  922.  
  923.     bell = !bell;
  924.     printf("Bell mode %s.\n", onoff(bell));
  925.     code = bell;
  926. }
  927.  
  928. /*
  929.  * Turn on packet tracing.
  930.  */
  931. /*VARARGS*/
  932. void
  933. settrace(int argc, char *argv[])
  934. {
  935.  
  936.     trace = !trace;
  937.     printf("Packet tracing %s.\n", onoff(trace));
  938.     code = trace;
  939. }
  940.  
  941. /*
  942.  * Toggle hash mark printing during transfers.
  943.  */
  944. /*VARARGS*/
  945. void
  946. sethash(int argc, char *argv[])
  947. {
  948.  
  949.     hash = !hash;
  950.     if (hash && tick)
  951.         settick(0, NULL);
  952.  
  953.     printf("Hash mark printing %s", onoff(hash));
  954.     code = hash;
  955.     if (hash)
  956.         printf(" (%d bytes/hash mark)", 1024);
  957.     printf(".\n");
  958. }
  959.  
  960. /*
  961.  * Toggle tick counter printing during transfers.
  962.  */
  963. /*VARARGS*/
  964. void
  965. settick(int argc, char *argv[])
  966. {
  967.     tick = !tick;
  968.     if (hash && tick)
  969.         sethash(0, NULL);
  970.     printf("Tick counter printing %s", onoff(tick));
  971.     code = tick;
  972.     if (tick)
  973.         printf(" (%d bytes/tick increment)", TICKBYTES);
  974.     printf(".\n");
  975. }
  976.  
  977. /*
  978.  * Turn on printing of server echo's.
  979.  */
  980. /*VARARGS*/
  981. void
  982. setverbose(int argc, char *argv[])
  983. {
  984.  
  985.     verbose = !verbose;
  986.     printf("Verbose mode %s.\n", onoff(verbose));
  987.     code = verbose;
  988. }
  989.  
  990. /*
  991.  * Toggle PORT cmd use before each data connection.
  992.  */
  993. /*VARARGS*/
  994. void
  995. setport(int argc, char *argv[])
  996. {
  997.  
  998.     sendport = !sendport;
  999.     printf("Use of PORT cmds %s.\n", onoff(sendport));
  1000.     code = sendport;
  1001. }
  1002.  
  1003. /*
  1004.  * Turn on interactive prompting
  1005.  * during mget, mput, and mdelete.
  1006.  */
  1007. /*VARARGS*/
  1008. void
  1009. setprompt(int argc, char *argv[])
  1010. {
  1011.  
  1012.     interactive = !interactive;
  1013.     printf("Interactive mode %s.\n", onoff(interactive));
  1014.     code = interactive;
  1015. }
  1016.  
  1017. /*
  1018.  * Toggle metacharacter interpretation
  1019.  * on local file names.
  1020.  */
  1021. /*VARARGS*/
  1022. void
  1023. setglob(int argc, char *argv[])
  1024. {
  1025.     
  1026.     doglob = !doglob;
  1027.     printf("Globbing %s.\n", onoff(doglob));
  1028.     code = doglob;
  1029. }
  1030.  
  1031. /*
  1032.  * Set debugging mode on/off and/or
  1033.  * set level of debugging.
  1034.  */
  1035. /*VARARGS*/
  1036. void
  1037. setdebug(argc, argv)
  1038.     int argc;
  1039.     char *argv[];
  1040. {
  1041.     int val;
  1042.  
  1043.     if (argc > 1) {
  1044.         val = atoi(argv[1]);
  1045.         if (val < 0) {
  1046.             printf("%s: bad debugging value.\n", argv[1]);
  1047.             code = -1;
  1048.             return;
  1049.         }
  1050.     } else
  1051.         val = !debug;
  1052.     debug = val;
  1053.     if (debug)
  1054.         options |= SO_DEBUG;
  1055.     else
  1056.         options &= ~SO_DEBUG;
  1057.     printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
  1058.     code = debug > 0;
  1059. }
  1060.  
  1061. /*
  1062.  * Set current working directory
  1063.  * on remote machine.
  1064.  */
  1065. void
  1066. cd(argc, argv)
  1067.     int argc;
  1068.     char *argv[];
  1069. {
  1070.  
  1071.     if (argc < 2 && !another(&argc, &argv, "remote-directory")) {
  1072.         printf("usage: %s remote-directory\n", argv[0]);
  1073.         code = -1;
  1074.         return;
  1075.     }
  1076.     if (command("CWD %s", argv[1]) == ERROR && code == 500) {
  1077.         if (verbose)
  1078.             printf("CWD command not recognized, trying XCWD\n");
  1079.         (void) command("XCWD %s", argv[1]);
  1080.     }
  1081. }
  1082.  
  1083. /*
  1084.  * Set current working directory
  1085.  * on local machine.
  1086.  */
  1087. void
  1088. lcd(argc, argv)
  1089.     int argc;
  1090.     char *argv[];
  1091. {
  1092.     char buf[MAXPATHLEN];
  1093.     extern char *getwd();
  1094.  
  1095.     if (argc < 2)
  1096.         argc++, argv[1] = home;
  1097.     if (argc != 2) {
  1098.         printf("usage: %s local-directory\n", argv[0]);
  1099.         code = -1;
  1100.         return;
  1101.     }
  1102.     if (!globulize(&argv[1])) {
  1103.         code = -1;
  1104.         return;
  1105.     }
  1106.     if (chdir(argv[1]) < 0) {
  1107.         fprintf(stderr, "local: %s: %s\n", argv[1], strerror(errno));
  1108.         code = -1;
  1109.         return;
  1110.     }
  1111.     printf("Local directory now %s\n", getwd(buf));
  1112.     code = 0;
  1113. }
  1114.  
  1115. /*
  1116.  * Delete a single file.
  1117.  */
  1118. void
  1119. delete_cmd(argc, argv)
  1120.     int argc;
  1121.     char *argv[];
  1122. {
  1123.  
  1124.     if (argc < 2 && !another(&argc, &argv, "remote-file")) {
  1125.         printf("usage: %s remote-file\n", argv[0]);
  1126.         code = -1;
  1127.         return;
  1128.     }
  1129.     (void) command("DELE %s", argv[1]);
  1130. }
  1131.  
  1132. /*
  1133.  * Delete multiple files.
  1134.  */
  1135. void
  1136. mdelete(argc, argv)
  1137.     int argc;
  1138.     char **argv;
  1139. {
  1140.     extern sigjmp_buf jabort;
  1141.     void (*oldintr)(int);
  1142.     int ointer;
  1143.     char *cp;
  1144.  
  1145.     if (argc < 2 && !another(&argc, &argv, "remote-files")) {
  1146.         printf("usage: %s remote-files\n", argv[0]);
  1147.         code = -1;
  1148.         return;
  1149.     }
  1150.     mname = argv[0];
  1151.     mflag = 1;
  1152.     oldintr = signal(SIGINT, mabort);
  1153.     (void) sigsetjmp(jabort, 1);
  1154.     while ((cp = remglob(argv,0)) != NULL) {
  1155.         if (*cp == '\0') {
  1156.             mflag = 0;
  1157.             continue;
  1158.         }
  1159.         if (mflag && confirm(argv[0], cp)) {
  1160.             (void) command("DELE %s", cp);
  1161.             if (!mflag && fromatty) {
  1162.                 ointer = interactive;
  1163.                 interactive = 1;
  1164.                 if (confirm("Continue with", "mdelete")) {
  1165.                     mflag++;
  1166.                 }
  1167.                 interactive = ointer;
  1168.             }
  1169.         }
  1170.     }
  1171.     (void) signal(SIGINT, oldintr);
  1172.     mflag = 0;
  1173. }
  1174.  
  1175. /*
  1176.  * Rename a remote file.
  1177.  */
  1178. void
  1179. renamefile(argc, argv)
  1180.     int argc;
  1181.     char *argv[];
  1182. {
  1183.  
  1184.     if (argc < 2 && !another(&argc, &argv, "from-name"))
  1185.         goto usage;
  1186.     if (argc < 3 && !another(&argc, &argv, "to-name")) {
  1187. usage:
  1188.         printf("%s from-name to-name\n", argv[0]);
  1189.         code = -1;
  1190.         return;
  1191.     }
  1192.     if (command("RNFR %s", argv[1]) == CONTINUE)
  1193.         (void) command("RNTO %s", argv[2]);
  1194. }
  1195.  
  1196. /*
  1197.  * Get a directory listing
  1198.  * of remote files.
  1199.  */
  1200. void
  1201. ls(argc, argv)
  1202.     int argc;
  1203.     char *argv[];
  1204. {
  1205.     char *cmd;
  1206.  
  1207.     if (argc < 2)
  1208.         argc++, argv[1] = NULL;
  1209.     if (argc < 3)
  1210.         argc++, argv[2] = "-";
  1211.     if (argc > 3) {
  1212.         printf("usage: %s remote-directory local-file\n", argv[0]);
  1213.         code = -1;
  1214.         return;
  1215.     }
  1216.     cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
  1217.     if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
  1218.         code = -1;
  1219.         return;
  1220.     }
  1221.     if (strcmp(argv[2], "-") && *argv[2] != '|')
  1222.         if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) {
  1223.             code = -1;
  1224.             return;
  1225.     }
  1226.     recvrequest(cmd, argv[2], argv[1], "w", 0);
  1227. }
  1228.  
  1229. /*
  1230.  * Get a directory listing
  1231.  * of multiple remote files.
  1232.  */
  1233. void
  1234. mls(argc, argv)
  1235.     int argc;
  1236.     char **argv;
  1237. {
  1238.     extern sigjmp_buf jabort;
  1239.     void (*oldintr)(int);
  1240.     int ointer, i;
  1241.     char *volatile cmd;
  1242.     char mode[1], *dest;
  1243.  
  1244.     if (argc < 2 && !another(&argc, &argv, "remote-files"))
  1245.         goto usage;
  1246.     if (argc < 3 && !another(&argc, &argv, "local-file")) {
  1247. usage:
  1248.         printf("usage: %s remote-files local-file\n", argv[0]);
  1249.         code = -1;
  1250.         return;
  1251.     }
  1252.     dest = argv[argc - 1];
  1253.     argv[argc - 1] = NULL;
  1254.     if (strcmp(dest, "-") && *dest != '|')
  1255.         if (!globulize(&dest) ||
  1256.             !confirm("output to local-file:", dest)) {
  1257.             code = -1;
  1258.             return;
  1259.     }
  1260.     cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
  1261.     mname = argv[0];
  1262.     mflag = 1;
  1263.     oldintr = signal(SIGINT, mabort);
  1264.  
  1265.     /*
  1266.      * This just plain seems wrong.
  1267.      */
  1268.     (void) sigsetjmp(jabort, 1);
  1269.  
  1270.     for (i = 1; mflag && i < argc-1; ++i) {
  1271.         *mode = (i == 1) ? 'w' : 'a';
  1272.         recvrequest(cmd, dest, argv[i], mode, 0);
  1273.         if (!mflag && fromatty) {
  1274.             ointer = interactive;
  1275.             interactive = 1;
  1276.             if (confirm("Continue with", argv[0])) {
  1277.                 mflag ++;
  1278.             }
  1279.             interactive = ointer;
  1280.         }
  1281.     }
  1282.     (void) signal(SIGINT, oldintr);
  1283.     mflag = 0;
  1284. }
  1285.  
  1286. /*
  1287.  * Do a shell escape
  1288.  */
  1289. /*ARGSUSED*/
  1290. void
  1291. shell(int argc, char *argv[])
  1292. {
  1293.     int pid;
  1294.     void (*old1)(int);
  1295.     void (*old2)(int);
  1296.     char shellnam[40], *shell, *namep; 
  1297.     union wait status;
  1298.  
  1299.     old1 = signal (SIGINT, SIG_IGN);
  1300.     old2 = signal (SIGQUIT, SIG_IGN);
  1301.     if ((pid = fork()) == 0) {
  1302.         for (pid = 3; pid < 20; pid++)
  1303.             (void) close(pid);
  1304.         (void) signal(SIGINT, SIG_DFL);
  1305.         (void) signal(SIGQUIT, SIG_DFL);
  1306.         shell = getenv("SHELL");
  1307.         if (shell == NULL)
  1308.             shell = _PATH_BSHELL;
  1309.         namep = rindex(shell,'/');
  1310.         if (namep == NULL)
  1311.             namep = shell;
  1312.         (void) strcpy(shellnam,"-");
  1313.         (void) strcat(shellnam, ++namep);
  1314.         if (strcmp(namep, "sh") != 0)
  1315.             shellnam[0] = '+';
  1316.         if (debug) {
  1317.             printf ("%s\n", shell);
  1318.             (void) fflush (stdout);
  1319.         }
  1320.         if (argc > 1) {
  1321.             execl(shell,shellnam,"-c",altarg,(char *)0);
  1322.         }
  1323.         else {
  1324.             execl(shell,shellnam,(char *)0);
  1325.         }
  1326.         perror(shell);
  1327.         code = -1;
  1328.         exit(1);
  1329.         }
  1330.     if (pid > 0)
  1331.         while (wait((int *)&status) != pid)
  1332.             ;
  1333.     (void) signal(SIGINT, old1);
  1334.     (void) signal(SIGQUIT, old2);
  1335.     if (pid == -1) {
  1336.         perror("Try again later");
  1337.         code = -1;
  1338.     }
  1339.     else {
  1340.         code = 0;
  1341.     }
  1342. }
  1343.  
  1344. /*
  1345.  * Send new user information (re-login)
  1346.  */
  1347. void
  1348. user(int argc, char *argv[])
  1349. {
  1350.     char acct[80], *getpass();
  1351.     int n, aflag = 0;
  1352.  
  1353.     if (argc < 2)
  1354.         (void) another(&argc, &argv, "username");
  1355.     if (argc < 2 || argc > 4) {
  1356.         printf("usage: %s username [password] [account]\n", argv[0]);
  1357.         code = -1;
  1358.         return;
  1359.     }
  1360.     n = command("USER %s", argv[1]);
  1361.     if (n == CONTINUE) {
  1362.         if (argc < 3 )
  1363.             argv[2] = getpass("Password: "), argc++;
  1364.         n = command("PASS %s", argv[2]);
  1365.     }
  1366.     if (n == CONTINUE) {
  1367.         if (argc < 4) {
  1368.             printf("Account: "); (void) fflush(stdout);
  1369.             (void) fgets(acct, sizeof(acct) - 1, stdin);
  1370.             acct[strlen(acct) - 1] = '\0';
  1371.             argv[3] = acct; argc++;
  1372.         }
  1373.         n = command("ACCT %s", argv[3]);
  1374.         aflag++;
  1375.     }
  1376.     if (n != COMPLETE) {
  1377.         fprintf(stdout, "Login failed.\n");
  1378.         return;
  1379.     }
  1380.     if (!aflag && argc == 4) {
  1381.         (void) command("ACCT %s", argv[3]);
  1382.     }
  1383. }
  1384.  
  1385. /*
  1386.  * Print working directory.
  1387.  */
  1388. /*VARARGS*/
  1389. void
  1390. pwd(int argc, char *argv[])
  1391. {
  1392.     int oldverbose = verbose;
  1393.  
  1394.     /*
  1395.      * If we aren't verbose, this doesn't do anything!
  1396.      */
  1397.     verbose = 1;
  1398.     if (command("PWD") == ERROR && code == 500) {
  1399.         printf("PWD command not recognized, trying XPWD\n");
  1400.         (void) command("XPWD");
  1401.     }
  1402.     verbose = oldverbose;
  1403. }
  1404.  
  1405. /*
  1406.  * Make a directory.
  1407.  */
  1408. void
  1409. makedir(argc, argv)
  1410.     int argc;
  1411.     char *argv[];
  1412. {
  1413.  
  1414.     if (argc < 2 && !another(&argc, &argv, "directory-name")) {
  1415.         printf("usage: %s directory-name\n", argv[0]);
  1416.         code = -1;
  1417.         return;
  1418.     }
  1419.     if (command("MKD %s", argv[1]) == ERROR && code == 500) {
  1420.         if (verbose)
  1421.             printf("MKD command not recognized, trying XMKD\n");
  1422.         (void) command("XMKD %s", argv[1]);
  1423.     }
  1424. }
  1425.  
  1426. /*
  1427.  * Remove a directory.
  1428.  */
  1429. void
  1430. removedir(argc, argv)
  1431.     int argc;
  1432.     char *argv[];
  1433. {
  1434.  
  1435.     if (argc < 2 && !another(&argc, &argv, "directory-name")) {
  1436.         printf("usage: %s directory-name\n", argv[0]);
  1437.         code = -1;
  1438.         return;
  1439.     }
  1440.     if (command("RMD %s", argv[1]) == ERROR && code == 500) {
  1441.         if (verbose)
  1442.             printf("RMD command not recognized, trying XRMD\n");
  1443.         (void) command("XRMD %s", argv[1]);
  1444.     }
  1445. }
  1446.  
  1447. /*
  1448.  * Send a line, verbatim, to the remote machine.
  1449.  */
  1450. void
  1451. quote(argc, argv)
  1452.     int argc;
  1453.     char *argv[];
  1454. {
  1455.  
  1456.     if (argc < 2 && !another(&argc, &argv, "command line to send")) {
  1457.         printf("usage: %s line-to-send\n", argv[0]);
  1458.         code = -1;
  1459.         return;
  1460.     }
  1461.     quote1("", argc, argv);
  1462. }
  1463.  
  1464. /*
  1465.  * Send a SITE command to the remote machine.  The line
  1466.  * is sent verbatim to the remote machine, except that the
  1467.  * word "SITE" is added at the front.
  1468.  */
  1469. void
  1470. site(argc, argv)
  1471.     int argc;
  1472.     char *argv[];
  1473. {
  1474.  
  1475.     if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
  1476.         printf("usage: %s line-to-send\n", argv[0]);
  1477.         code = -1;
  1478.         return;
  1479.     }
  1480.     quote1("SITE ", argc, argv);
  1481. }
  1482.  
  1483. /*
  1484.  * Turn argv[1..argc) into a space-separated string, then prepend initial text.
  1485.  * Send the result as a one-line command and get response.
  1486.  */
  1487. static void
  1488. quote1(char *initial, int argc, char **argv)
  1489. {
  1490.     register int i, len;
  1491.     char buf[BUFSIZ];        /* must be >= sizeof(line) */
  1492.  
  1493.     (void) strcpy(buf, initial);
  1494.     if (argc > 1) {
  1495.         len = strlen(buf);
  1496.         len += strlen(strcpy(&buf[len], argv[1]));
  1497.         for (i = 2; i < argc; i++) {
  1498.             buf[len++] = ' ';
  1499.             len += strlen(strcpy(&buf[len], argv[i]));
  1500.         }
  1501.     }
  1502.     if (command(buf) == PRELIM) {
  1503.         while (getreply(0) == PRELIM);
  1504.     }
  1505. }
  1506.  
  1507. void
  1508. do_chmod(argc, argv)
  1509.     int argc;
  1510.     char *argv[];
  1511. {
  1512.  
  1513.     if (argc < 2 && !another(&argc, &argv, "mode"))
  1514.         goto usage;
  1515.     if (argc < 3 && !another(&argc, &argv, "file-name")) {
  1516. usage:
  1517.         printf("usage: %s mode file-name\n", argv[0]);
  1518.         code = -1;
  1519.         return;
  1520.     }
  1521.     (void) command("SITE CHMOD %s %s", argv[1], argv[2]);
  1522. }
  1523.  
  1524. void
  1525. do_umask(argc, argv)
  1526.     int argc;
  1527.     char *argv[];
  1528. {
  1529.     int oldverbose = verbose;
  1530.  
  1531.     verbose = 1;
  1532.     (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
  1533.     verbose = oldverbose;
  1534. }
  1535.  
  1536. void
  1537. idle_cmd(argc, argv)
  1538.     int argc;
  1539.     char *argv[];
  1540. {
  1541.     int oldverbose = verbose;
  1542.  
  1543.     verbose = 1;
  1544.     (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
  1545.     verbose = oldverbose;
  1546. }
  1547.  
  1548. /*
  1549.  * Ask the other side for help.
  1550.  */
  1551. void
  1552. rmthelp(argc, argv)
  1553.     int argc;
  1554.     char *argv[];
  1555. {
  1556.     int oldverbose = verbose;
  1557.  
  1558.     verbose = 1;
  1559.     (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
  1560.     verbose = oldverbose;
  1561. }
  1562.  
  1563. /*
  1564.  * Terminate session and exit.
  1565.  */
  1566. /*VARARGS*/
  1567. void
  1568. quit(int argc, char *argv[])
  1569. {
  1570.  
  1571.     if (connected)
  1572.         disconnect(0, NULL);
  1573.     pswitch(1);
  1574.     if (connected) {
  1575.         disconnect(0, NULL);
  1576.     }
  1577.     exit(0);
  1578. }
  1579.  
  1580. /*
  1581.  * Terminate session, but don't exit.
  1582.  */
  1583. void
  1584. disconnect(int argc, char *argv[])
  1585. {
  1586.     extern FILE *cout;
  1587.     extern int data;
  1588.  
  1589.     if (!connected)
  1590.         return;
  1591.     (void) command("QUIT");
  1592.     if (cout) {
  1593.         (void) fclose(cout);
  1594.     }
  1595.     cout = NULL;
  1596.     connected = 0;
  1597.     data = -1;
  1598.     if (!proxy) {
  1599.         macnum = 0;
  1600.     }
  1601. }
  1602.  
  1603. static int
  1604. confirm(char *cmd, char *file)
  1605. {
  1606.     char line[BUFSIZ];
  1607.  
  1608.     if (!interactive)
  1609.         return (1);
  1610.     printf("%s %s? ", cmd, file);
  1611.     (void) fflush(stdout);
  1612.     if (fgets(line, sizeof line, stdin) == NULL)
  1613.         return (0);
  1614.     return (*line != 'n' && *line != 'N');
  1615. }
  1616.  
  1617. void
  1618. fatal(const char *msg)
  1619. {
  1620.  
  1621.     fprintf(stderr, "ftp: %s\n", msg);
  1622.     exit(1);
  1623. }
  1624.  
  1625. /*
  1626.  * Glob a local file name specification with
  1627.  * the expectation of a single return value.
  1628.  * Can't control multiple values being expanded
  1629.  * from the expression, we return only the first.
  1630.  */
  1631. static int
  1632. globulize(char **cpp)
  1633. {
  1634.     char **globbed;
  1635.  
  1636.     if (!doglob)
  1637.         return (1);
  1638.     globbed = ftpglob(*cpp);
  1639.     if (globerr != NULL) {
  1640.         printf("%s: %s\n", *cpp, globerr);
  1641.         if (globbed) {
  1642.             blkfree(globbed);
  1643.             free((char *)globbed);
  1644.         }
  1645.         return (0);
  1646.     }
  1647.     if (globbed) {
  1648.         *cpp = *globbed++;
  1649.         /* don't waste too much memory */
  1650.         if (*globbed) {
  1651.             blkfree(globbed);
  1652.             free((char *)globbed);
  1653.         }
  1654.     }
  1655.     return (1);
  1656. }
  1657.  
  1658. void
  1659. account(argc,argv)
  1660.     int argc;
  1661.     char **argv;
  1662. {
  1663.     char acct[50], *getpass(), *ap;
  1664.  
  1665.     if (argc > 1) {
  1666.         ++argv;
  1667.         --argc;
  1668.         (void) strncpy(acct,*argv,49);
  1669.         acct[49] = '\0';
  1670.         while (argc > 1) {
  1671.             --argc;
  1672.             ++argv;
  1673.             (void) strncat(acct,*argv, 49-strlen(acct));
  1674.         }
  1675.         ap = acct;
  1676.     }
  1677.     else {
  1678.         ap = getpass("Account:");
  1679.     }
  1680.     (void) command("ACCT %s", ap);
  1681. }
  1682.  
  1683. sigjmp_buf abortprox;
  1684.  
  1685. void
  1686. proxabort(int argc, char *argv[])
  1687. {
  1688.     extern int proxy;
  1689.  
  1690.     if (!proxy) {
  1691.         pswitch(1);
  1692.     }
  1693.     if (connected) {
  1694.         proxflag = 1;
  1695.     }
  1696.     else {
  1697.         proxflag = 0;
  1698.     }
  1699.     pswitch(0);
  1700.     siglongjmp(abortprox,1);
  1701. }
  1702.  
  1703. static void sigproxabort(int ignore) 
  1704. {
  1705.     proxabort(0, NULL);
  1706. }
  1707.  
  1708. void
  1709. doproxy(argc,argv)
  1710.     int argc;
  1711.     char *argv[];
  1712. {
  1713.     extern sigjmp_buf abortprox;
  1714.     register struct cmd *c;
  1715.     struct cmd *getcmd();
  1716.     void (*oldintr)(int);
  1717.     void proxabort();
  1718.  
  1719.     if (argc < 2 && !another(&argc, &argv, "command")) {
  1720.         printf("usage: %s command\n", argv[0]);
  1721.         code = -1;
  1722.         return;
  1723.     }
  1724.     c = getcmd(argv[1]);
  1725.     if (c == (struct cmd *) -1) {
  1726.         printf("?Ambiguous command\n");
  1727.         (void) fflush(stdout);
  1728.         code = -1;
  1729.         return;
  1730.     }
  1731.     if (c == 0) {
  1732.         printf("?Invalid command\n");
  1733.         (void) fflush(stdout);
  1734.         code = -1;
  1735.         return;
  1736.     }
  1737.     if (!c->c_proxy) {
  1738.         printf("?Invalid proxy command\n");
  1739.         (void) fflush(stdout);
  1740.         code = -1;
  1741.         return;
  1742.     }
  1743.     if (sigsetjmp(abortprox, 1)) {
  1744.         code = -1;
  1745.         return;
  1746.     }
  1747.     oldintr = signal(SIGINT, sigproxabort);
  1748.     pswitch(1);
  1749.     if (c->c_conn && !connected) {
  1750.         printf("Not connected\n");
  1751.         (void) fflush(stdout);
  1752.         pswitch(0);
  1753.         (void) signal(SIGINT, oldintr);
  1754.         code = -1;
  1755.         return;
  1756.     }
  1757.     (*c->c_handler)(argc-1, argv+1);
  1758.     if (connected) {
  1759.         proxflag = 1;
  1760.     }
  1761.     else {
  1762.         proxflag = 0;
  1763.     }
  1764.     pswitch(0);
  1765.     (void) signal(SIGINT, oldintr);
  1766. }
  1767.  
  1768. void
  1769. setcase(int argc, char *argv[])
  1770. {
  1771.     mcase = !mcase;
  1772.     printf("Case mapping %s.\n", onoff(mcase));
  1773.     code = mcase;
  1774. }
  1775.  
  1776. void
  1777. setcr(int argc, char *argv[])
  1778. {
  1779.     crflag = !crflag;
  1780.     printf("Carriage Return stripping %s.\n", onoff(crflag));
  1781.     code = crflag;
  1782. }
  1783.  
  1784. void
  1785. setntrans(argc,argv)
  1786.     int argc;
  1787.     char *argv[];
  1788. {
  1789.     if (argc == 1) {
  1790.         ntflag = 0;
  1791.         printf("Ntrans off.\n");
  1792.         code = ntflag;
  1793.         return;
  1794.     }
  1795.     ntflag++;
  1796.     code = ntflag;
  1797.     (void) strncpy(ntin, argv[1], 16);
  1798.     ntin[16] = '\0';
  1799.     if (argc == 2) {
  1800.         ntout[0] = '\0';
  1801.         return;
  1802.     }
  1803.     (void) strncpy(ntout, argv[2], 16);
  1804.     ntout[16] = '\0';
  1805. }
  1806.  
  1807. char *
  1808. dotrans(name)
  1809.     char *name;
  1810. {
  1811.     static char new[MAXPATHLEN];
  1812.     char *cp1, *cp2 = new;
  1813.     register int i, ostop, found;
  1814.  
  1815.     for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++);
  1816.     for (cp1 = name; *cp1; cp1++) {
  1817.         found = 0;
  1818.         for (i = 0; *(ntin + i) && i < 16; i++) {
  1819.             if (*cp1 == *(ntin + i)) {
  1820.                 found++;
  1821.                 if (i < ostop) {
  1822.                     *cp2++ = *(ntout + i);
  1823.                 }
  1824.                 break;
  1825.             }
  1826.         }
  1827.         if (!found) {
  1828.             *cp2++ = *cp1;
  1829.         }
  1830.     }
  1831.     *cp2 = '\0';
  1832.     return(new);
  1833. }
  1834.  
  1835. void
  1836. setnmap(argc, argv)
  1837.     int argc;
  1838.     char *argv[];
  1839. {
  1840.     char *cp;
  1841.  
  1842.     if (argc == 1) {
  1843.         mapflag = 0;
  1844.         printf("Nmap off.\n");
  1845.         code = mapflag;
  1846.         return;
  1847.     }
  1848.     if (argc < 3 && !another(&argc, &argv, "mapout")) {
  1849.         printf("Usage: %s [mapin mapout]\n",argv[0]);
  1850.         code = -1;
  1851.         return;
  1852.     }
  1853.     mapflag = 1;
  1854.     code = 1;
  1855.     cp = index(altarg, ' ');
  1856.     if (proxy) {
  1857.         while(*++cp == ' ');
  1858.         altarg = cp;
  1859.         cp = index(altarg, ' ');
  1860.     }
  1861.     *cp = '\0';
  1862.     (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
  1863.     while (*++cp == ' ');
  1864.     (void) strncpy(mapout, cp, MAXPATHLEN - 1);
  1865. }
  1866.  
  1867. char *
  1868. domap(name)
  1869.     char *name;
  1870. {
  1871.     static char new[MAXPATHLEN];
  1872.     register char *cp1 = name, *cp2 = mapin;
  1873.     char *tp[9], *te[9];
  1874.     int i, toks[9], toknum = 0, match = 1;
  1875.  
  1876.     for (i=0; i < 9; ++i) {
  1877.         toks[i] = 0;
  1878.     }
  1879.     while (match && *cp1 && *cp2) {
  1880.         switch (*cp2) {
  1881.             case '\\':
  1882.                 if (*++cp2 != *cp1) {
  1883.                     match = 0;
  1884.                 }
  1885.                 break;
  1886.             case '$':
  1887.                 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
  1888.                     if (*cp1 != *(++cp2+1)) {
  1889.                         toks[toknum = *cp2 - '1']++;
  1890.                         tp[toknum] = cp1;
  1891.                         while (*++cp1 && *(cp2+1)
  1892.                             != *cp1);
  1893.                         te[toknum] = cp1;
  1894.                     }
  1895.                     cp2++;
  1896.                     break;
  1897.                 }
  1898.                 /* FALLTHROUGH */
  1899.             default:
  1900.                 if (*cp2 != *cp1) {
  1901.                     match = 0;
  1902.                 }
  1903.                 break;
  1904.         }
  1905.         if (match && *cp1) {
  1906.             cp1++;
  1907.         }
  1908.         if (match && *cp2) {
  1909.             cp2++;
  1910.         }
  1911.     }
  1912.     if (!match && *cp1) /* last token mismatch */
  1913.     {
  1914.         toks[toknum] = 0;
  1915.     }
  1916.     cp1 = new;
  1917.     *cp1 = '\0';
  1918.     cp2 = mapout;
  1919.     while (*cp2) {
  1920.         match = 0;
  1921.         switch (*cp2) {
  1922.             case '\\':
  1923.                 if (*(cp2 + 1)) {
  1924.                     *cp1++ = *++cp2;
  1925.                 }
  1926.                 break;
  1927.             case '[':
  1928. LOOP:
  1929.                 if (*++cp2 == '$' && isdigit(*(cp2+1))) { 
  1930.                     if (*++cp2 == '0') {
  1931.                         char *cp3 = name;
  1932.  
  1933.                         while (*cp3) {
  1934.                             *cp1++ = *cp3++;
  1935.                         }
  1936.                         match = 1;
  1937.                     }
  1938.                     else if (toks[toknum = *cp2 - '1']) {
  1939.                         char *cp3 = tp[toknum];
  1940.  
  1941.                         while (cp3 != te[toknum]) {
  1942.                             *cp1++ = *cp3++;
  1943.                         }
  1944.                         match = 1;
  1945.                     }
  1946.                 }
  1947.                 else {
  1948.                     while (*cp2 && *cp2 != ',' && 
  1949.                         *cp2 != ']') {
  1950.                         if (*cp2 == '\\') {
  1951.                             cp2++;
  1952.                         }
  1953.                         else if (*cp2 == '$' &&
  1954.                                    isdigit(*(cp2+1))) {
  1955.                             if (*++cp2 == '0') {
  1956.                                char *cp3 = name;
  1957.  
  1958.                                while (*cp3) {
  1959.                                 *cp1++ = *cp3++;
  1960.                                }
  1961.                             }
  1962.                             else if (toks[toknum =
  1963.                                 *cp2 - '1']) {
  1964.                                char *cp3=tp[toknum];
  1965.  
  1966.                                while (cp3 !=
  1967.                                   te[toknum]) {
  1968.                                 *cp1++ = *cp3++;
  1969.                                }
  1970.                             }
  1971.                         }
  1972.                         else if (*cp2) {
  1973.                             *cp1++ = *cp2++;
  1974.                         }
  1975.                     }
  1976.                     if (!*cp2) {
  1977.                         printf("nmap: unbalanced brackets\n");
  1978.                         return(name);
  1979.                     }
  1980.                     match = 1;
  1981.                     cp2--;
  1982.                 }
  1983.                 if (match) {
  1984.                     while (*++cp2 && *cp2 != ']') {
  1985.                           if (*cp2 == '\\' && *(cp2 + 1)) {
  1986.                             cp2++;
  1987.                           }
  1988.                     }
  1989.                     if (!*cp2) {
  1990.                         printf("nmap: unbalanced brackets\n");
  1991.                         return(name);
  1992.                     }
  1993.                     break;
  1994.                 }
  1995.                 switch (*++cp2) {
  1996.                     case ',':
  1997.                         goto LOOP;
  1998.                     case ']':
  1999.                         break;
  2000.                     default:
  2001.                         cp2--;
  2002.                         goto LOOP;
  2003.                 }
  2004.                 break;
  2005.             case '$':
  2006.                 if (isdigit(*(cp2 + 1))) {
  2007.                     if (*++cp2 == '0') {
  2008.                         char *cp3 = name;
  2009.  
  2010.                         while (*cp3) {
  2011.                             *cp1++ = *cp3++;
  2012.                         }
  2013.                     }
  2014.                     else if (toks[toknum = *cp2 - '1']) {
  2015.                         char *cp3 = tp[toknum];
  2016.  
  2017.                         while (cp3 != te[toknum]) {
  2018.                             *cp1++ = *cp3++;
  2019.                         }
  2020.                     }
  2021.                     break;
  2022.                 }
  2023.                 /* intentional drop through */
  2024.             default:
  2025.                 *cp1++ = *cp2;
  2026.                 break;
  2027.         }
  2028.         cp2++;
  2029.     }
  2030.     *cp1 = '\0';
  2031.     if (!*new) {
  2032.         return(name);
  2033.     }
  2034.     return(new);
  2035. }
  2036.  
  2037. void
  2038. setsunique(int argc, char *argv[])
  2039. {
  2040.     sunique = !sunique;
  2041.     printf("Store unique %s.\n", onoff(sunique));
  2042.     code = sunique;
  2043. }
  2044.  
  2045. void
  2046. setrunique(int argc, char *argv[])
  2047. {
  2048.     runique = !runique;
  2049.     printf("Receive unique %s.\n", onoff(runique));
  2050.     code = runique;
  2051. }
  2052.  
  2053. /* change directory to parent directory */
  2054. void
  2055. cdup(int argc, char *argv[])
  2056. {
  2057.     if (command("CDUP") == ERROR && code == 500) {
  2058.         if (verbose)
  2059.             printf("CDUP command not recognized, trying XCUP\n");
  2060.         (void) command("XCUP");
  2061.     }
  2062. }
  2063.  
  2064. /* restart transfer at specific point */
  2065. void
  2066. restart(argc, argv)
  2067.     int argc;
  2068.     char *argv[];
  2069. {
  2070.     extern long atol();
  2071.     if (argc != 2)
  2072.         printf("restart: offset not specified\n");
  2073.     else {
  2074.         restart_point = atol(argv[1]);
  2075.         printf("restarting at %ld. %s\n", restart_point,
  2076.             "execute get, put or append to initiate transfer");
  2077.     }
  2078. }
  2079.  
  2080. /* show remote system type */
  2081. void
  2082. syst(int argc, char *argv[])
  2083. {
  2084.     command("SYST");
  2085. }
  2086.  
  2087. void
  2088. macdef(argc, argv)
  2089.     int argc;
  2090.     char *argv[];
  2091. {
  2092.     char *tmp;
  2093.     int c;
  2094.  
  2095.     if (macnum == 16) {
  2096.         printf("Limit of 16 macros have already been defined\n");
  2097.         code = -1;
  2098.         return;
  2099.     }
  2100.     if (argc < 2 && !another(&argc, &argv, "macro name")) {
  2101.         printf("Usage: %s macro_name\n",argv[0]);
  2102.         code = -1;
  2103.         return;
  2104.     }
  2105.     if (interactive) {
  2106.         printf("Enter macro line by line, terminating it with a null line\n");
  2107.     }
  2108.     (void) strncpy(macros[macnum].mac_name, argv[1], 8);
  2109.     if (macnum == 0) {
  2110.         macros[macnum].mac_start = macbuf;
  2111.     }
  2112.     else {
  2113.         macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
  2114.     }
  2115.     tmp = macros[macnum].mac_start;
  2116.     while (tmp != macbuf+4096) {
  2117.         if ((c = getchar()) == EOF) {
  2118.             printf("macdef:end of file encountered\n");
  2119.             code = -1;
  2120.             return;
  2121.         }
  2122.         if ((*tmp = c) == '\n') {
  2123.             if (tmp == macros[macnum].mac_start) {
  2124.                 macros[macnum++].mac_end = tmp;
  2125.                 code = 0;
  2126.                 return;
  2127.             }
  2128.             if (*(tmp-1) == '\0') {
  2129.                 macros[macnum++].mac_end = tmp - 1;
  2130.                 code = 0;
  2131.                 return;
  2132.             }
  2133.             *tmp = '\0';
  2134.         }
  2135.         tmp++;
  2136.     }
  2137.     while (1) {
  2138.         while ((c = getchar()) != '\n' && c != EOF)
  2139.             /* LOOP */;
  2140.         if (c == EOF || getchar() == '\n') {
  2141.             printf("Macro not defined - 4k buffer exceeded\n");
  2142.             code = -1;
  2143.             return;
  2144.         }
  2145.     }
  2146. }
  2147.  
  2148. /*
  2149.  * Start up passive mode interaction
  2150.  */
  2151. void
  2152. setpassive(int argc, char *argv[])
  2153. {
  2154.         passivemode = !passivemode;
  2155.         printf("Passive mode %s.\n", onoff(passivemode));
  2156.         code = passivemode;
  2157. }
  2158.  
  2159. /*
  2160.  * get size of file on remote machine
  2161.  */
  2162. void
  2163. sizecmd(argc, argv)
  2164.     int argc;
  2165.     char *argv[];
  2166. {
  2167.  
  2168.     if (argc < 2 && !another(&argc, &argv, "filename")) {
  2169.         printf("usage: %s filename\n", argv[0]);
  2170.         code = -1;
  2171.         return;
  2172.     }
  2173.     (void) command("SIZE %s", argv[1]);
  2174. }
  2175.  
  2176. /*
  2177.  * get last modification time of file on remote machine
  2178.  */
  2179. void
  2180. modtime(argc, argv)
  2181.     int argc;
  2182.     char *argv[];
  2183. {
  2184.     int overbose;
  2185.  
  2186.     if (argc < 2 && !another(&argc, &argv, "filename")) {
  2187.         printf("usage: %s filename\n", argv[0]);
  2188.         code = -1;
  2189.         return;
  2190.     }
  2191.     overbose = verbose;
  2192.     if (debug == 0)
  2193.         verbose = -1;
  2194.     if (command("MDTM %s", argv[1]) == COMPLETE) {
  2195.         int yy, mo, day, hour, min, sec;
  2196.         sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
  2197.             &day, &hour, &min, &sec);
  2198.         /* might want to print this in local time */
  2199.         printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
  2200.             mo, day, yy, hour, min, sec);
  2201.     } else
  2202.         printf("%s\n", reply_string);
  2203.     verbose = overbose;
  2204. }
  2205.  
  2206. /*
  2207.  * show status on remote machine
  2208.  */
  2209. void
  2210. rmtstatus(argc, argv)
  2211.     int argc;
  2212.     char *argv[];
  2213. {
  2214.     (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
  2215. }
  2216.  
  2217. /*
  2218.  * get file if modtime is more recent than current file
  2219.  */
  2220. void
  2221. newer(argc, argv)
  2222.     int argc;
  2223.     char *argv[];
  2224. {
  2225.     if (getit(argc, argv, -1, "w"))
  2226.         printf("Local file \"%s\" is newer than remote file \"%s\"\n",
  2227.             argv[2], argv[1]);
  2228. }
  2229.